package com.seuic.hnapps.util;

import java.io.ByteArrayOutputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.Cipher;

import com.solab.enc.HexT;



public class RSAUtils {
    /**
     * �����㷨RSA
     */
    public static final String KEY_ALGORITHM = "RSA";
    /**
     * ��ȡ��Կ��key
     */
    public static final String PUBLIC_KEY = "RSAPublicKey";
    
    /**
     * ��ȡ˽Կ��key
     */
    public static final String PRIVATE_KEY = "RSAPrivateKey";
    /**
     * RSA���������Ĵ�С
     */
    private static final int MAX_ENCRYPT_BLOCK = 117;    
    /**
     * RSA���������Ĵ�С
     */
    private static final int MAX_DECRYPT_BLOCK = 128;    
    

    /**
     * <p>
     * ������Կ��(��Կ��˽Կ)
     * </p>
     * 
     * @return
     * @throws Exception
     */
    public static Map<String, Object> genKeyPair() throws Exception {
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        keyPairGen.initialize(1024);
        KeyPair keyPair = keyPairGen.generateKeyPair();
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
        Map<String, Object> keyMap = new HashMap<String, Object>(2);
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);
        return keyMap;
    }

	
    /**
     * <p>
     * ��Կ����
     * </p>
     * 
     * @param data Դ����
     * @param publicKey ��Կ
     * @return
     * @throws Exception
     */
/*    */
    public static byte[] encryptByPublicKey(byte[] data, byte[]  publicKey)
            throws Exception {
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKey);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key publicK = keyFactory.generatePublic(x509KeySpec);
        // �����ݼ���
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicK);
        int inputLen = data.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // �����ݷֶμ���
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(data, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_ENCRYPT_BLOCK;
        }
        byte[] encryptedData = out.toByteArray();
        out.close();
        return encryptedData;
    }
	
	
    /**
     * <P>
     * ˽Կ����
     * </p>
     * 
     * @param encryptedData �Ѽ�������
     * @param privateKey ˽Կ
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPrivateKey(byte[] encryptedData, byte[] privateKey)
            throws Exception {
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKey);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
        
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateK);
        int inputLen = encryptedData.length;
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] cache;
        int i = 0;
        // �����ݷֶν���
        while (inputLen - offSet > 0) {
            if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
            }
            out.write(cache, 0, cache.length);
            i++;
            offSet = i * MAX_DECRYPT_BLOCK;
        }
        byte[] decryptedData = out.toByteArray();
        out.close();
        return decryptedData;
    } 
 /*   */ 
	public static void main(String args[])
	{
		Map<String, Object> keyMap = null;
		RSAPublicKey publicKey  = null;
		RSAPrivateKey privateKey = null;
		
		try {
			keyMap = genKeyPair();
			publicKey = (RSAPublicKey) keyMap.get(PUBLIC_KEY);
			privateKey = (RSAPrivateKey) keyMap.get(PRIVATE_KEY);
			
			String data = "E0EAED75CAD4DDD57C5D4B89F388AEBB";
			byte[] mib1 = null,mib2 = null;
			
			mib1 = encryptByPublicKey(data.getBytes(),publicKey.getEncoded());
			System.out.println("mib1=["+HexT.byteArr2HexStr(mib1)+"]");
			
			mib2 = decryptByPrivateKey(mib1,privateKey.getEncoded());
			System.out.println("mib2=["+new String(mib2)+"]");
			
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
   
}
